#pragma once
#include <iostream>
#include <functional>
#include <vector>
#include <memory>
#include <unordered_map>
#include <unistd.h>
#include <sys/timerfd.h>
#include "EventLoop.hpp"
using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask//定时任务
{
public:
    TimerTask(uint64_t id, uint32_t timeout, const TaskFunc& taskCallBack)
        :_id(id)
        ,_timeout(timeout)
        ,_taskCallBack(taskCallBack)
        ,_canceled(false)
    {}
    ~TimerTask()
    {
        if(_canceled == false)//任务没有被取消
        {
            _taskCallBack();//执行任务回调（销毁任务）
        }
        _releaseFunc();
    }
public:
    void SetRelease(const ReleaseFunc& taskCallBack)//TimerWheel类中传入的删除方法，用于删除TimerWheel中保存的定时器std::unordered_map<uint64_t, WeakPtrTask>信息
    {
        _releaseFunc = taskCallBack;
    }
    uint32_t GetTimeout() const
    {
        return _timeout;
    }
    void Cancel()//取消定时任务
    {
        _canceled = true;
    }
private:
    uint64_t _id;//定时器任务对象id
    uint32_t _timeout;//定时任务的超时时间 
    bool _canceled;//定时任务是否可以被取消，true表示被取消
    TaskFunc _taskCallBack;//定时器对象要执行的定时任务
    ReleaseFunc _releaseFunc;//TimerWheel类中传入的删除方法，用于删除TimerWheel中保存的定时器std::unordered_map<uint64_t, WeakPtrTask>信息
};


class TimerWheel//时间轮
{
public:
    TimerWheel(EventLoop* loop)
        :_wheel(_capacity)//包含_capacity个元素的vector
        ,_tick(0)
        ,_capacity(60)/*60秒*/
        ,_loop(loop)
        ,_timerfd(CreateTimerfd())
        ,_timerChannel(std::make_unique<Channel>(_loop, _timerfd))
    {
        _timerChannel->SetReadCallback(std::bind(&TimerWheel::OnTime, this));//设置可读事件的回调(这里是读取timerfd的内容)
        _timerChannel->EnableRead();//启动读事件监控
    } 
public:
    //向时间轮添加定时任务(销毁任务),定时器中有个timerfd，定时器信息的操作在多线程中操作存在线程安全问题
    //不想加锁就把定时器的所有操作，都放到一个线程中进行（这个id用于确认同一线程）
    void TimerAdd(uint64_t id, uint32_t timeout, const TaskFunc& taskCallBack);//这里是声明，定义在EventLoop.hpp中
    //在时间轮中刷新定时任务（在unordered_map找到弱指针，通过弱指针构造共享指针）
    void TimerRefresh(uint64_t id);//这里是声明，定义在EventLoop.hpp中
    //取消定时任务
    void TimerCancel(uint64_t id);//这里是声明，定义在EventLoop.hpp中
    //检测是否存在某个定时器任务(该接口因为返回bool，存在线程安全问题，不能被外界使用者调用，只能在EventLoop线程中调用)
    bool HasTimer(uint64_t id) 
    { 
        auto it = _timers.find(id);
        if (it == _timers.end()) { return false; }
        return true;
    }
private:
    using SharedPtrTask = std::shared_ptr<TimerTask>;//相当于typedef
    using WeakPtrTask = std::weak_ptr<TimerTask>;//相当于typedef
    //传入TimerTask类中，作为unordered_map<uint64_t, WeakPtrTask>中任务的删除函数
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it != _timers.end())
        {
            _timers.erase(it);
        }
    }
    //返回定时器文件描述符
    static int CreateTimerfd()
    {
        int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
        if(timerfd < 0)
        {
            ERROR_LOG("TIMERFD CREATE FAILED!");
            abort();
        }
        struct itimerspec itime;
        itime.it_value.tv_sec = 1;//First timeout time,3 seconds.
        itime.it_value.tv_nsec = 0;//Prevent random numbers and set the time to zero.
        itime.it_interval.tv_sec = 1;//After the first timeout, the time for subsequent timeouts,3 seconds.
        itime.it_interval.tv_nsec = 0;
        timerfd_settime(timerfd, 0, &itime, nullptr);
        return timerfd;
    }
    //读取_timefd中的内容
    void ReadTimerfd()
    {
        uint64_t timesBuffer;//从文件描述符timerfd中读取超时了多少次
        int ret = read(_timerfd, &timesBuffer, 8);
        if(ret < 0)
        {
            ERROR_LOG("READ TIMEFD FAILED!");
            abort();
        }
    }
    //秒针滴答，每秒执行一次
    void TickRun()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();//清空指定位置的数组元素，释放数组中所有保存的定时器对象的共享指针
    }
    //定时时间到了
    void OnTime()
    {
        // ReadTimerfd();//读取_timerfd中的内容(清空_timerfd)
        // RunTimerTask();
        //根据实际超时的次数，执行对应的超时任务
        ReadTimerfd();
        TickRun();
    }
    //向时间轮添加定时任务(销毁任务)(TimerAdd的子函数)
    void TimerAddInLoop(uint64_t id, uint32_t timeout, const TaskFunc& taskCallBack)
    {
        SharedPtrTask pt(new TimerTask(id, timeout, taskCallBack));//对定时器任务创建共享指针  
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));//设置移除函数
        _wheel[(_tick + timeout) % _capacity].push_back(pt);//将共享指针插入数组
        _timers[id] = WeakPtrTask(pt);//在unordered_map中填充弱指针，根据共享指针构造一个弱指针，不会让计数器+1
    }
    //在时间轮中刷新定时任务（在unordered_map找到弱指针，通过弱指针构造共享指针）(TimerRefresh的子函数)
    void TimerRefreshInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
        {
            return;//在unordered_map中没找到弱指针
        }
        SharedPtrTask pt = it->second.lock();//通过lock获取weak_ptr所管理的对象
        int timeout = pt->GetTimeout();//获取定时任务的初始延时时间
        _wheel[(_tick + timeout) % _capacity].push_back(pt);//将生成的共享指针插入数组
    }
    //取消定时任务,TimerCancel的子函数
    void TimerCancelInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
        {
            return;//在unordered_map中没找到弱指针
        }
        SharedPtrTask pt = it->second.lock();//通过lock获取weak_ptr所管理的对象
        if(pt)//共享指针pt可能为空
        {
            pt->Cancel();
        }
    }
private:
    int _capacity;//时间轮的最大刻度（最大延时时间）
    std::vector<std::vector<SharedPtrTask>> _wheel;//轮
    int _tick;//秒针，滴答下标，走到哪就释放哪的对象
    std::unordered_map<uint64_t, WeakPtrTask> _timers;//<定时器任务对象id, 弱指针>
    EventLoop* _loop;//定时器锁关联的EventLoop
    int _timerfd;//定时器的文件描述符，可读事件的回调就是读取该文件描述符，执行定时任务(通过EventLoop模块对该fd进行事件监控)
    std::unique_ptr<Channel> _timerChannel;//管理定时器的Channel模块,管理定时器IO事件的回调
}; 